#!/usr/bin/env python
#
'''
Created on 2009-3-30

@author: Wang_Yuan
'''

import os
import sys
import random
import wx
import wx.wizard as wiz
import wx.lib.mixins.listctrl as listmix

import core
import Meaning2wordPanel_xrc
import Example2wordPanel_xrc
import Word2meaningsPanel_xrc

class ShowWordDetailMixin:
    def __init__(self, answerCtrl, wordData):
        self.wordData = wordData
        self.answerCtrl = answerCtrl
        self.detailFrame = None
        answerCtrl.SetToolTipString('Click to get word detail...')
        answerCtrl.Bind(wx.EVT_LEFT_DOWN, self.OnShowWordDetail)
        
    def OnShowWordDetail(self, evt):
        import WordDetailFrame
        mPos = self.answerCtrl.ClientToScreen(evt.GetPosition())
        if not self.detailFrame:
            self.detailFrame = WordDetailFrame.WordDetailFrame(self, self.wordData)
        size = self.detailFrame.GetSize()
        pos = (mPos[0], max(0, mPos[1] - size[1]))
        self.detailFrame.SetPosition(pos)
        self.detailFrame.Show(True)
        
class PlaySoundMixin:
    def __init__(self, wordData):
        self.wordData = wordData
        
    def OnChanged(self, evt):
        if self.prev is None:
            core.sound.asyncLoadWord(self.wordData.word, 5)
        else:
            core.sound.playWord()

class TitleMixin:
    def __init__(self, index, prev):
        title = '%s - %s' % ('Answer' if prev is not None else 'Question', (index))
        self.title.SetLabel(title)
        
class PhraseMarkMixin:
    BGCOLOR = wx.Color(red=0xdd, green=0xff, blue=0xff)
    def __init__(self, inputCtrl, wordData):
        print wordData.word
        if wordData.isPhrase():
            inputCtrl.SetBackgroundColour(PhraseMarkMixin.BGCOLOR)
            inputCtrl.SetToolTipString('phrase')

class Meaning2WordPanel(Meaning2wordPanel_xrc.xrcMeaning2WordPanel, 
                        ShowWordDetailMixin, TitleMixin, PlaySoundMixin, PhraseMarkMixin):
    '''
    Meaning2Word Panel
    '''
    
    def __init__(self, parent, index, questionList, prev=None):
        Meaning2wordPanel_xrc.xrcMeaning2WordPanel.__init__(self, parent)
        TitleMixin.__init__(self, index, prev)
        question = questionList[index]
        self.question = question
        if prev is not None:
            ShowWordDetailMixin.__init__(self, self.rightAnswerText, self.question.wordData)
        PhraseMarkMixin.__init__(self, self.yourAnswerText, self.question.wordData)
        PlaySoundMixin.__init__(self, self.question.wordData)
        self.questionList = questionList
        self.meaningList = question.meaningList
        self.answer = question.answer
        self.prev = prev
        wordData = question.wordData
        self.shownMeaningList = wordData.getNonEnglishMeaningList() + wordData.getEnglishMeaningList() if prev is not None else self.meaningList[0:1]
        self.refreshMeaningsText()
        self.rightAnswerText.SetValue(self.answer)
        self.answerPanel.Show(prev is not None)
        self.moreMeaningPanel.Show(prev is None)
        if prev is not None:
            self.evaluateAnswer()
            self.recordScore()
            self.title.SetFocus()
        else:
            self.yourAnswerText.SetFocus()
        self.yourAnswerText.SetEditable(prev is None)
                
    def OnChanging(self, evt):
        if self.prev is None:
            if not self.isAnswered():
                wx.MessageBox('Please input your answer!', caption='Alert', style=wx.OK|wx.ICON_WARNING)
                evt.Veto()
                self.yourAnswerText.SetFocus()
        else:
            evt.Skip()

    def OnButton_moreMeaning(self, evt):
        if not self.prev is not None:
            self.shownMeaningList.append(self.meaningList[len(self.shownMeaningList)])
            self.refreshMeaningsText()
        else:
            evt.Skip()
            
    def isAnswered(self):
        return bool(self.yourAnswerText.GetValue())
        
    def refreshMeaningsText(self):
        self.meaningsText.ChangeValue(os.linesep.join(self.shownMeaningList))
        self.meaningsText.Refresh()
        self.moreMeaning.Enable(self.prev is None and len(self.shownMeaningList) < len(self.meaningList))
        
    def evaluateAnswer(self):
        yourAnswer = self.prev.yourAnswerText.GetValue()
        if yourAnswer:
            self.yourAnswerText.SetValue(yourAnswer)
            if yourAnswer.strip() == self.answer:
                bg = wx.NamedColor('green')
                fg = wx.NamedColor('black')
            else:
                bg = wx.NamedColor('red')
                fg = wx.NamedColor('white')
                            
            self.yourAnswerText.SetBackgroundColour(bg)
            self.yourAnswerText.SetForegroundColour(fg)
        
    def recordScore(self):
        yourAnswer = self.prev.yourAnswerText.GetValue()
        if yourAnswer:
            score = 0
            if yourAnswer.strip() == self.answer:
                denominator = len(self.meaningList) - 1
                numerator = len(self.prev.shownMeaningList) - 1
                if numerator < denominator:
                    ratio = float(numerator) / float(denominator)
                else:
                    ratio = 1 if numerator > 0 else 0
                score = 5 + int(round(5 * (1 - ratio)))
            self.question.recordScore(score)
            if score < 7:
                self.question.addOXRecord(False)
                self.questionList[0].append(self.question)
            else:
                self.question.addOXRecord(True)
            
            
class Example2WordPanel(Example2wordPanel_xrc.xrcExample2WordPanel, 
                        ShowWordDetailMixin, TitleMixin, PlaySoundMixin, PhraseMarkMixin):
    '''
    Example -> Word Panel
    '''
    
    def __init__(self, parent, index, questionList, prev=None):
        Example2wordPanel_xrc.xrcExample2WordPanel.__init__(self, parent)
        TitleMixin.__init__(self, index, prev)
        self.question = questionList[index]
        if prev is not None:
            ShowWordDetailMixin.__init__(self, self.rightAnswerText, self.question.wordData)
        PhraseMarkMixin.__init__(self, self.yourAnswerText, self.question.wordData)
        PlaySoundMixin.__init__(self, self.question.wordData)
        self.questionList = questionList
        self.example = self.question.example
        self.answer = self.question.answer
        self.rightAnswerText.ChangeValue(self.answer)
        self.prev = prev
        self.showTranslationFlag = prev is not None
        self.showTranslation.Enable(not self.showTranslationFlag)
        self.refreshExampleText()
        self.answerPanel.Show(prev is not None)
        self.showTranslationPanel.Show(prev is None)
        if prev is not None:
            self.evaluateAnswer()
            self.recordScore()
            self.title.SetFocus()
        else:
            self.yourAnswerText.SetFocus()
        self.yourAnswerText.SetEditable(prev is None)
        
    def OnChanging(self, evt):
        if self.prev is None:
            if not self.isAnswered():
                wx.MessageBox('Please input your answer!', caption='Alert', style=wx.OK|wx.ICON_WARNING)
                evt.Veto()
                self.yourAnswerText.SetFocus()
        else:
            evt.Skip()

    def OnButton_showTranslation(self, evt):
        self.showTranslationFlag = True
        self.showTranslation.Enable(not self.showTranslationFlag)
        self.refreshExampleText()

    def OnText_yourAnswerText(self, evt):
        self.refreshExampleText()
        
    def isAnswered(self):
        return bool(self.yourAnswerText.GetValue())
        
    def refreshExampleText(self):
        yourAnswer = self.yourAnswerText.GetValue()
        if self.prev is not None:
            replace = self.answer
        elif yourAnswer.strip():
            replace = yourAnswer
        else:
            replace = u'_______'
        text = '%s %s %s' % (self.example.front, replace, self.example.after)
        if self.showTranslationFlag:
            text += os.linesep + self.example.translation
        self.exampleText.ChangeValue(text)
    
    def evaluateAnswer(self):
        yourAnswer = self.prev.yourAnswerText.GetValue()
        if yourAnswer:
            self.yourAnswerText.SetValue(yourAnswer)
            if yourAnswer.strip() == self.answer:
                bg = wx.NamedColor('green')
                fg = wx.NamedColor('black')
                self.question.addOXRecord(True)
            else:
                bg = wx.NamedColor('red')
                fg = wx.NamedColor('white')
                self.question.addOXRecord(False)
                self.questionList[0].append(self.question)
                            
            self.yourAnswerText.SetBackgroundColour(bg)
            self.yourAnswerText.SetForegroundColour(fg)
        
    def recordScore(self):
        yourAnswer = self.prev.yourAnswerText.GetValue()
        if yourAnswer:
            score = 0
            if yourAnswer.strip() == self.answer:
                if self.prev.showTranslationFlag:
                    score = 7
                else:
                    score = 10
            self.question.recordScore(score)
            

class CustomListCtrl(wx.ListCtrl, listmix.CheckListCtrlMixin, listmix.ListCtrlAutoWidthMixin):
    def __init__(self):
        listmix.CheckListCtrlMixin.__init__(self)
        listmix.ListCtrlAutoWidthMixin.__init__(self)
        self.setResizeColumn(0)
        self.Unbind(wx.EVT_LEFT_DOWN)

class Word2MeaningsPanel(Word2meaningsPanel_xrc.xrcWord2MeaningsPanel, ShowWordDetailMixin, TitleMixin, PlaySoundMixin):
    '''
    Word -> Meanings Panel
    '''
    
    def __init__(self, parent, index, questionList, prev=None):
        Word2meaningsPanel_xrc.xrcWord2MeaningsPanel.__init__(self, parent)
        TitleMixin.__init__(self, index, prev)
        self.question = questionList[index]
        if prev is not None:
            ShowWordDetailMixin.__init__(self, self.wordText, self.question.wordData)
        PlaySoundMixin.__init__(self, self.question.wordData)
        self.questionList = questionList
        self.prev = prev
        self.wordText.SetLabel(self.question.word)
        self.pronunciationText.SetLabel(self.question.pronunciation)
        self.answerMeaningList = self.question.meaningList
        self.answerSet = set(self.answerMeaningList)
        self.createAnswerCandidates()
        self.yourAnswerList.Set(self.candidateList)
        self.answerPanel.Show(prev is not None)
        self.yourAnswerPanel.Show(prev is None)
        if prev is not None:
            self.rightAnswerList.__class__ = CustomListCtrl
            CustomListCtrl.__init__(self.rightAnswerList)
            self.setupRightAnswer()
#            self.evaluateAnswer()
            self.recordScore()
            self.title.SetFocus()
        else:
            self.yourAnswerList.SetFocus()
        # self.yourAnswerList.Enable(prev is None)
        
    def OnChanging(self, evt):
        if self.prev is None:
            if not self.isAnswered():
                wx.MessageBox('Please select your answer!', caption='Alert', style=wx.OK|wx.ICON_WARNING)
                evt.Veto()
                self.yourAnswerList.SetFocus()
        else:
            evt.Skip()
        
    def getYourAnswer(self):
        l = []
        for i in xrange(self.yourAnswerList.GetCount()):
            if self.yourAnswerList.IsChecked(i):
                l.append(self.yourAnswerList.GetString(i))
                
        return l
    
    def isAnswered(self):
        return bool(self.getYourAnswer())
        
    def createAnswerCandidates(self):
        LEAST_NUM = 3
        if self.prev is None:
            ql = list(self.question.vocabulary.data)
            ql.remove(self.question.wordData)
            meanings = list()
            for q in ql:
                meanings += q.getNonEnglishAtomMeaningList()
            random.shuffle(meanings)
            interferon = set()
            for i in xrange(max(random.randint(1, len(self.answerMeaningList)), LEAST_NUM)):
                if meanings:
                    interferon.add(meanings.pop())
            self.candidateList = self.answerMeaningList + list(interferon)
            random.shuffle(self.candidateList)
        else:
            self.candidateList = self.prev.candidateList
        
    def setupRightAnswer(self):
        imageList = self.rightAnswerList.GetImageList(wx.IMAGE_LIST_SMALL)
        correctIcon = imageList.Add(wx.Bitmap('ui/img/icon_tick.gif', type=wx.BITMAP_TYPE_GIF))
        wrongIcon = imageList.Add(wx.Bitmap('ui/img/icon_cross.gif', type=wx.BITMAP_TYPE_GIF))
        self.rightAnswerList.InsertColumn(0, 'Answer')
        self.rightAnswerList.InsertColumn(1, 'mark')
        yourAnswer = self.prev.getYourAnswer()
        yourAnswerSet = set(yourAnswer)
        incorrectCount = 0
        for m in self.candidateList:
            index = self.rightAnswerList.InsertStringItem(sys.maxint, m)
            font = self.rightAnswerList.GetItemFont(index)
            correct = True
            if m not in self.answerSet:
                font.SetWeight(wx.FONTWEIGHT_LIGHT)
                self.rightAnswerList.SetItemTextColour(index, wx.NamedColor('gray'))
                if m in yourAnswerSet:
                    correct = False
                    incorrectCount += 1
            else:
                font.SetWeight(wx.FONTWEIGHT_BOLD)
                self.rightAnswerList.SetItemTextColour(index, wx.NamedColor('blue'))
                if m not in yourAnswerSet:
                    correct = False
                    incorrectCount += 1
            self.rightAnswerList.SetItemFont(index, font)
            if m in yourAnswerSet:
                self.rightAnswerList.CheckItem(index)
                
            self.rightAnswerList.SetItemColumnImage(index, 1, correctIcon if correct else wrongIcon)
            # self.rightAnswerList.SetColumnWidth(0, self.rightAnswerList.GetSize()[0])
            self.rightAnswerList.SetColumnWidth(1, 18)
            #self.rightAnswerList.SetItemBackgroundColour(index, wx.NamedColor('green' if correct else 'red'))
            if index % 2:
                self.rightAnswerList.SetItemBackgroundColour(index, wx.Color(red=0xee, green=0xee, blue=0xee))
        if incorrectCount == len(self.candidateList):
            # all wrong
            self.scoreBar.SetBackgroundColour(wx.RED)
        elif incorrectCount == 0:
            # all correct
            self.scoreBar.SetBackgroundColour(wx.GREEN)
        else:
            self.scoreBar.SetBackgroundColour(wx.NamedColor('yellow'))
        
    def recordScore(self):
        yourAnswer = self.prev.getYourAnswer()
        yourAnswerSet = set(yourAnswer)
        if yourAnswer:
            score = 0
            if yourAnswerSet == self.answerSet:
                score = 10
            elif yourAnswerSet.issubset(self.answerSet):
                score = 5 + int(round(len(yourAnswerSet) * 5. / len(self.answerSet)))
                
            self.question.recordScore(score)
            if score < 7:
                self.question.addOXRecord(False)
                self.questionList[0].append(self.question)
            else:
                self.question.addOXRecord(True)

def getQuestionPanelBuilder(index, questionList):
    panelClasses = [
                    Meaning2WordPanel, 
                    Example2WordPanel, 
                    Word2MeaningsPanel, 
                    ]
    question = questionList[index]
    qTypeIndex = question.typeIndex
    def getQuestionPanel(parent):
        return panelClasses[qTypeIndex](parent, index, questionList)
    
    return getQuestionPanel

def getAnswerPanelBuilder(index, questionList, prev):
    panelClasses = [
                    Meaning2WordPanel, 
                    Example2WordPanel, 
                    Word2MeaningsPanel, 
                    ]
    question = questionList[index]
    qTypeIndex = question.typeIndex
    def getAnswerPanel(parent):
        return panelClasses[qTypeIndex](parent, index, questionList, prev)
    
    return getAnswerPanel
